﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Ink;
using AgilePlannerDT.Display;
using AgilePlannerDT.Data.Impl;
using AgilePlannerDT.Data;
using AgilePlannerDT.Utils;
using AgilePlannerDT.Window;
using AgilePlannerDT.Display.Impl;
using System.Windows.Threading;
using AgilePlannerDT.Application.Commands.Impl;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Input;
//for automation
using System.Windows.Automation;
using System.Windows.Automation.Peers;
using System.Windows.Automation.Provider;
using ShapeRecognizer.Objects;
using System.Windows.Shapes;

namespace AgilePlannerDT.Application.Modules.Impl
{
    public class GestureModuleImpl : AbstractApplicationModule, GestureModule
    {
        InkCanvas surface;
        GestureRecognizer gestureRecognizer;

        public GestureModuleImpl(AgilePlannerApplication app, Dispatcher dispatcher, InkCanvas surface, GestureRecognizer gestureRecognizer)
        {
            this.app = app;
            this.dispatcher = dispatcher;
           this.surface = surface;

            this.gestureRecognizer = gestureRecognizer;

            //initialize the InkCanvas gesture recognitino
            if (surface.IsGestureRecognizerAvailable)
            {
                surface.EditingMode = InkCanvasEditingMode.GestureOnly;
                surface.Gesture += new InkCanvasGestureEventHandler(ProcessGesture);
                surface.SetEnabledGestures(new ApplicationGesture[] {  

                    //create storycard
                    ApplicationGesture.ChevronDown,
                    ApplicationGesture.ChevronLeft,
                    ApplicationGesture.ChevronRight,
                    ApplicationGesture.ChevronUp,
                    
                    //create iteration
                    ApplicationGesture.Square,

                    //delete card
                    ApplicationGesture.ScratchOut,
                    ApplicationGesture.LeftRight,
                    ApplicationGesture.RightLeft,
                    ApplicationGesture.UpDown,
                    ApplicationGesture.DownUp,

                    //undo
                    ApplicationGesture.LeftDown,
                    ApplicationGesture.UpLeft,
                    ApplicationGesture.RightUp,
                    ApplicationGesture.DownRight,

                    //redo
                    ApplicationGesture.RightDown,
                    ApplicationGesture.UpRight,
                    ApplicationGesture.LeftUp,
                    ApplicationGesture.DownLeft,    
                
                    //minimize/recover the cards
                 
                    ApplicationGesture.Left,
                    ApplicationGesture.Right,
                    ApplicationGesture.Up,
                    ApplicationGesture.Down,

                    //recover floatToolBox
                    ApplicationGesture.Circle,

                    //create textArea
                    ApplicationGesture.ArrowDown,
                    ApplicationGesture.ArrowLeft,
                    ApplicationGesture.ArrowRight,
                    ApplicationGesture.ArrowUp,

                    //create statusArea
                    ApplicationGesture.Triangle
                });

            }

            //surface.Background = Brushes.Transparent;
            surface.DefaultDrawingAttributes.Color = Colors.GreenYellow;

            gestureRecognizer.SetEnabledGestures(new ApplicationGesture[] {
                    ApplicationGesture.ScratchOut,
               //     ApplicationGesture.Right,
                 //   ApplicationGesture.Left
            });
        }
        

        public GestureModuleImpl(AgilePlannerApplication app, Dispatcher dispatcher, GestureRecognizer gestureRecognizer)
        {

            this.app = app;
            this.dispatcher = dispatcher;
       //     this.surface = surface;

            this.gestureRecognizer = gestureRecognizer;
/*
            //initialize the InkCanvas gesture recognitino
            if (surface.IsGestureRecognizerAvailable)
            {
                surface.EditingMode = InkCanvasEditingMode.GestureOnly;
                surface.Gesture += new InkCanvasGestureEventHandler(ProcessGesture);
                surface.SetEnabledGestures(new ApplicationGesture[] {  

                    //create storycard
                    ApplicationGesture.ChevronDown,
                    ApplicationGesture.ChevronLeft,
                    ApplicationGesture.ChevronRight,
                    ApplicationGesture.ChevronUp,
                    
                    //create iteration
                    ApplicationGesture.Square,

                    //delete card
                    ApplicationGesture.ScratchOut,
                    ApplicationGesture.LeftRight,
                    ApplicationGesture.RightLeft,
                    ApplicationGesture.UpDown,
                    ApplicationGesture.DownUp,

                    //undo
                    ApplicationGesture.LeftDown,
                    ApplicationGesture.UpLeft,
                    ApplicationGesture.RightUp,
                    ApplicationGesture.DownRight,

                    //redo
                    ApplicationGesture.RightDown,
                    ApplicationGesture.UpRight,
                    ApplicationGesture.LeftUp,
                    ApplicationGesture.DownLeft,    
                
                    //minimize/recover the cards
                 
                    ApplicationGesture.Left,
                    ApplicationGesture.Right,
                    ApplicationGesture.Up,
                    ApplicationGesture.Down,

                    //recover floatToolBox
                    ApplicationGesture.Circle,

                    //create textArea
                    ApplicationGesture.ArrowDown,
                    ApplicationGesture.ArrowLeft,
                    ApplicationGesture.ArrowRight,
                    ApplicationGesture.ArrowUp,

                    //create statusArea
                    ApplicationGesture.Triangle
                });

            }

            //surface.Background = Brushes.Transparent;
            surface.DefaultDrawingAttributes.Color = Colors.GreenYellow;
           
            gestureRecognizer.SetEnabledGestures(new ApplicationGesture[] {
                    ApplicationGesture.ScratchOut,
               //     ApplicationGesture.Right,
                 //   ApplicationGesture.Left
            });*/
        
        }

        public GestureRecognizer GestureRecognizer
        {
            get { return this.gestureRecognizer; }
        }

   /*     public InkCanvas Surface
        {
            get { return this.surface; }
        }*/

        public void ProcessGesture(object sender, InkCanvasGestureEventArgs e)
        {
            if( !(sender is AgilePlannerMainWindow || sender is AgilePlannerMicrosoftSurfaceWindow)&&!(sender is InkCanvas))
                return;
           string recognizedShape = "";
            //Analyze Gesture by using 
           try
           {
               if (e.Strokes.Count > 0)
               {
                   Stroke stroke = e.Strokes[0];

                   // Calculate the boundary rectangle
                   Rect rect = stroke.GetBounds();
                   Rectangle rectangle = new Rectangle();
                   rectangle.Height = rect.Height;
                   rectangle.Width = rect.Width;

                   // Convert stylus points to regular Point[] 
                   Point[] points = new Point[stroke.StylusPoints.Count];
                   int index = 0;
                   foreach (StylusPoint point in stroke.StylusPoints)
                   {
                       Point p = new Point() { X = point.X - rect.X, Y = point.Y - rect.Y };
                       points[index++] = p;
                   }

                   ShapeRecognizer.ShapeRecognizer shapeRecognizer = new ShapeRecognizer.ShapeRecognizer(points, rectangle);

                   // Show what shape we have dectected from the stroke
                   GeometricShape geometricShape = shapeRecognizer.GetShape();
                   recognizedShape = geometricShape.ShapeType.ToString();

               }
           }
           catch (Exception)
           {
               recognizedShape = "";
           }

            ApplicationGesture topGesture = e.GetGestureRecognitionResults()[0].ApplicationGesture;
            #region showfloatToolBox
            if (topGesture == ApplicationGesture.Circle || recognizedShape.Equals("Circle"))
            {

                //stop the tossing pallete
                ((DisplayObjectImpl)Application.ToolBox).getanimationStoryBoard().Stop((DisplayObjectImpl)Application.ToolBox);

                Rect gestureBounds = e.Strokes.GetBounds();

                Point gestureCenter = new Point(gestureBounds.TopLeft.X + gestureBounds.Width / 2,
                    gestureBounds.TopLeft.Y + gestureBounds.Height / 2);
                ((DisplayObjectImpl)Application.ToolBox).Move(gestureCenter.X - ((DisplayObjectImpl)Application.ToolBox).CenterAbsolute.X,
                   gestureCenter.Y - ((DisplayObjectImpl)Application.ToolBox).CenterAbsolute.Y);
                //  ((FloatingToolBox)Application.ToolBox).Visibility = Visibility.Visible;
                Application.ToolBox.FadeIn();
                return;
            }
            #endregion




            else if (topGesture == ApplicationGesture.ChevronUp ||
                topGesture == ApplicationGesture.ChevronDown ||
                topGesture == ApplicationGesture.ChevronLeft ||
                topGesture == ApplicationGesture.ChevronRight ||
                topGesture == ApplicationGesture.ArrowUp ||
                    topGesture == ApplicationGesture.ArrowRight ||
                    topGesture == ApplicationGesture.ArrowLeft ||
                    topGesture == ApplicationGesture.ArrowDown)
            #region Create StoryCard or TextArea
            {
                Boolean isTextArea = true;
                if (topGesture == ApplicationGesture.ChevronUp ||
                topGesture == ApplicationGesture.ChevronDown ||
                topGesture == ApplicationGesture.ChevronLeft ||
                topGesture == ApplicationGesture.ChevronRight)
                    isTextArea = false;
                if (Application.Project == null)
                {
                    return;
                }

                Rect gestureBounds = e.Strokes.GetBounds();
                Point gestureCenter = new Point(gestureBounds.TopLeft.X + gestureBounds.Width / 2,
                    gestureBounds.TopLeft.Y + gestureBounds.Height / 2);

                if (Application.Project == null)
                {
                    //don't do anything if no project has been selected
                }
                else
                {

                    long pid = Application.Project.Backlog.ID;

                    StoryCard sc = new StoryCardDataObject();

                    foreach (DisplayObject card in Application.Cards.Values)
                    {
                        if (card.Contains(gestureCenter))
                        {
                            if (card is IterationDisplayObjectImpl ||
                                card is StateAreaDisplayObjectImpl)
                            {
                                pid = card.ID;
                            }
                       }
                    }

                    float rotationAngle = 0;

                    switch (topGesture)
                    {
                        case ApplicationGesture.ChevronDown:
                            rotationAngle = 180f;
                            break;
                        case ApplicationGesture.ArrowDown:
                            rotationAngle = 180f;
                            break;
                        case ApplicationGesture.ChevronLeft:
                            rotationAngle = 270f;
                            break;
                        case ApplicationGesture.ArrowLeft:
                            rotationAngle = 270f;
                            break;
                        case ApplicationGesture.ChevronRight:
                            rotationAngle = 90f;
                            break;
                        case ApplicationGesture.ArrowRight:
                            rotationAngle = 90f;
                            break;
                        default:
                            rotationAngle = 0f;
                            break;
                    }

                    if (Application.Persister != null)
                    {
                        int cardHeight = (int)sc.Height;
                        string cardColor = (string)(new CardColorConverter().ConvertTo(Application.DefaultColor, typeof(string)));
                        string description = sc.Description;
                        if (isTextArea)
                        {
                            cardHeight = (int)CardConstants.TEXTAREA_DEFAULT_HEIGHT;
                            cardColor = "transparent";
                            description = "text area";
                        }
                        Application.Persister.CreateStoryCard(sc.Name, description, (int)sc.Width, cardHeight,
                            (int)(-CardConstants.STORYCARD_DEFAULT_WIDTH / 2 + gestureBounds.TopLeft.X / Properties.Settings.Default.Scale + gestureBounds.Width / (Properties.Settings.Default.Scale * 2)), 
                            (int)(-CardConstants.STORYCARD_DEFAULT_HEIGHT / 2 + gestureBounds.TopLeft.Y / Properties.Settings.Default.Scale + gestureBounds.Height / (Properties.Settings.Default.Scale*2)), 
                            pid, sc.BestCaseEstimate, sc.MostlikelyEstimate, sc.WorstCaseEstimate, sc.ActualEffort, sc.Status, cardColor, sc.CardOwner, rotationAngle);
                        
                        /*foreach (DisplayObject card in Application.Cards.Values)
                        {
                            if (card.Contains(gestureCenter))
                            {
                                if (card is IterationDisplayObjectImpl ||
                                    card is StateAreaDisplayObjectImpl)
                                {
                                    Application.Persister.MoveStoryCardToNewParent(sc, card.ID, 
                                        (int) sc.LocationX, (int) sc.LocationY, (float) sc.RotationAngle);
                                }
                            }
                        }  */
                       /* if (parent != null) 
                        {
                            if (parent is IterationDisplayObjectImpl)
                                ((IterationDisplayObjectImpl)parent).AddStoryCard(
                                    (StoryCardDisplayObject) Application.Cards[Application.Cards.Count - 1]);
                            else if (parent is StateAreaDisplayObjectImpl)
                                ((StateAreaDisplayObjectImpl)parent).AddStoryCard(
                                    (StoryCardDisplayObject) Application.Cards[Application.Cards.Count - 1]);
                        }*/

                    }
                    else
                    {
                        // else, do nothing
                    }
                }
            }
            #endregion
            else if (topGesture == ApplicationGesture.Square || recognizedShape.Equals("Rectangle"))
            #region Create Iteration
            {
                if (Application.Project == null)
                {
                    // do nothing if no project has been loaded
                    return;
                }

                Rect gestureBounds = e.Strokes.GetBounds();

                Iteration iteration = new IterationDataObject();

                int width = (gestureBounds.Width/Properties.Settings.Default.Scale > CardConstants.ITERATION_DEFAULT_WIDTH ? (int)(gestureBounds.Width/Properties.Settings.Default.Scale) : (int)CardConstants.ITERATION_DEFAULT_WIDTH);
                int height = ((int)gestureBounds.Height/Properties.Settings.Default.Scale > CardConstants.ITERATION_DEFAULT_HEIGHT ? (int)(gestureBounds.Height/Properties.Settings.Default.Scale) : (int)CardConstants.ITERATION_DEFAULT_HEIGHT);

                if (Application.Persister != null)
                {
                    Application.Persister.CreateIteration(iteration.Name, iteration.Description, width, height,
                        (int)(gestureBounds.TopLeft.X/Properties.Settings.Default.Scale), (int)(gestureBounds.TopLeft.Y/Properties.Settings.Default.Scale), iteration.AvailableEffort, iteration.StartDate, iteration.EndDate);
                }
                else
                {
                    // else, no action is needed
                }
            }
            #endregion
            else if ((topGesture == ApplicationGesture.ScratchOut ||
                topGesture == ApplicationGesture.DownUp ||
                topGesture == ApplicationGesture.UpDown ||
                topGesture == ApplicationGesture.LeftRight ||
                topGesture == ApplicationGesture.RightLeft || recognizedShape.Equals("Zigzag")) &&
                //gesture not on top of storycard
                (!(sender is StoryCardDisplayObjectImpl)))
            #region Delete
            {
                if (Application.Project == null)
                {
                    // no project loaded, do nothing
                    return;
                }

                Rect gestureBounds = e.Strokes.GetBounds();

                Point gestureCenter = new Point(gestureBounds.TopLeft.X + gestureBounds.Width / 2,
                    gestureBounds.TopLeft.Y + gestureBounds.Height / 2);

                //collect the cards to be deleted
                List<StoryCardDisplayObject> delsc = new List<StoryCardDisplayObject>();
                List<IterationDisplayObject> deliter = new List<IterationDisplayObject>();

                foreach (DisplayObject card in Application.Cards.Values)
                {
                    foreach (StylusPoint point in e.Strokes[0].StylusPoints)
                    {
                         if (card.Contains(new Point(point.X, point.Y)))
                        //make sure that the target card is really CROSSED out
                        /*     if (card.Contains(gestureCenter)
                                 && !card.Contains(gestureBounds.TopLeft)
                                 && !card.Contains(gestureBounds.BottomRight))*/
                        {
                            if (card is IterationDisplayObject)
                            {
                                //            if (MessageBox.Show("Really delete?", "Confirm delete", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
                                //             {
                                deliter.Add((IterationDisplayObject)card);
                                //             }
                            }
                            else if (card is StoryCardDisplayObject&&card.ParentID== Application.Project.Backlog.ID)
                            {
                                delsc.Add((StoryCardDisplayObject)card);
                            }
                            break;
                        }
                    }
                }

                //if there's iterations to delete don't bother with storycards
                if (deliter.Count > 0)
                {
                    foreach (IterationDisplayObject iter in deliter)
                    {
                        if (Application.Persister != null)
                        {
                            Application.Delete(iter);
                        }
                    }
                }
                //if there's only storycards delete them
                 if(delsc.Count > 0)
                {
                    foreach (StoryCardDisplayObject sc in delsc)
                    {
                        if (Application.Persister != null)
                        {
                            Application.Delete(sc);
                        }
                    }
                }

            }
            #endregion
            else if (topGesture == ApplicationGesture.LeftDown ||
                    topGesture == ApplicationGesture.UpLeft ||
                    topGesture == ApplicationGesture.RightUp ||
                    topGesture == ApplicationGesture.DownRight)
            #region Undo
            {
                if (Application.Project == null)
                {
                    return;
                }

                int last = Application.Commands.Count - 1;

                //find the last command in the list, that has not been
                //reverted yet
                for (int i = last; i >= 0; i--)
                {
                    if (!Application.Commands[i].IsUndone)
                    {
                        Application.Commands[i].Undo();
                        break;
                    }
                }
            }
            #endregion
            else if (topGesture == ApplicationGesture.RightDown ||
                    topGesture == ApplicationGesture.UpRight ||
                    topGesture == ApplicationGesture.LeftUp ||
                    topGesture == ApplicationGesture.DownLeft)
            #region Redo
            {
                if (Application.Project == null)
                {
                    return;
                }

                int last = Application.Commands.Count - 1;

                //for (int i = 0; i < last; i++)
                //{
                //    //find the first command in the list that has been
                //    //reverted before
                //    if (Application.Commands[i].IsUndone)
                //    {
                //        Application.Commands[i].Redo();
                //        break;
                //    }
                //}

                if (last >= 0)
                    Application.Commands[last].Redo();
            }
            #endregion
            #region MinimizeCard
            else if (topGesture == ApplicationGesture.Left ||
                topGesture == ApplicationGesture.Right ||
                topGesture == ApplicationGesture.Up ||
                topGesture == ApplicationGesture.Down||recognizedShape.Equals("Line"))
            {
                if (Application.Project == null)
                {
                    return;
                }

                Rect gestureBounds = e.Strokes.GetBounds();

                Point gestureCenter = new Point(gestureBounds.TopLeft.X + gestureBounds.Width / 2,
                    gestureBounds.TopLeft.Y + gestureBounds.Height / 2);

                foreach (DisplayObject card in Application.Cards.Values)
                {
                  //  e.Strokes[0].StylusPoints[0].
                    //make sure that the target card is really CROSSED out
                    foreach (StylusPoint point in e.Strokes[0].StylusPoints)
                    {
                        if (card.Contains(new Point(point.X, point.Y)))
                        //          && !card.Contains(gestureBounds.TopLeft)
                        //         && !card.Contains(gestureBounds.BottomRight))
                        {
                            if (card is StoryCardDisplayObject)
                            {
                                if (this.app.Persister is AgilePlannerDT.Persister.Impl.AsyncWrapperPersister)
                                    this.app.Persister.MinimizeCard(card.ID);
                                else
                                {
                                    StoryCard sc;
                                    StoryCardDisplayObjectImpl sccard = (StoryCardDisplayObjectImpl)card;
                                    if (sccard.StoryCardData.Height != CardConstants.DEFAULT_MINIMIZED_CARD_HEIGHT)
                                    {
                                        sc = (StoryCard)sccard.StoryCardData.Clone();
                                        sc.Height = CardConstants.DEFAULT_MINIMIZED_CARD_HEIGHT;
                                    }
                                    else
                                    {
                                        sc = (StoryCard)sccard.StoryCardData.Clone();
                                        sc.Height = CardConstants.STORYCARD_DEFAULT_HEIGHT;
                                    }


                                    this.app.Persister.UpdateStoryCard(sc);
                                }
                            }
                            break;
                        }
                    }
                }
            }
            #endregion

            #region StateArea
            /**
             * Gesture support for Triangle.  
             * Creates a new Iteration object and displays it to the screen.
             * However, this Iteration object displays as a StateArea.
             */
            else if (topGesture == ApplicationGesture.Triangle || recognizedShape.Equals("Triangle")) 
            {
                if (Application.Project == null)
                {
                    return;
                }

                Iteration statearea = new StateDataObject();

                Rect gestureBounds = e.Strokes.GetBounds();

                int width = (gestureBounds.Width / Properties.Settings.Default.Scale
                    > CardConstants.STATEAREA_DEFAULT_WIDTH 
                    ? (int)(gestureBounds.Width / Properties.Settings.Default.Scale)
                    : (int)CardConstants.STATEAREA_DEFAULT_WIDTH);
                int height = ((int)gestureBounds.Height / Properties.Settings.Default.Scale
                    > CardConstants.STATEAREA_DEFAULT_HEIGHT
                    ? (int)(gestureBounds.Height / Properties.Settings.Default.Scale)
                    : (int)CardConstants.STATEAREA_DEFAULT_HEIGHT);

                if (Application.Persister != null)
                {
                    Application.Persister.CreateIteration(statearea.Name, statearea.Description, 
                        width, height, (int)(gestureBounds.TopLeft.X / Properties.Settings.Default.Scale), 
                        (int)(gestureBounds.TopLeft.Y / Properties.Settings.Default.Scale),
                        statearea.AvailableEffort, statearea.StartDate, statearea.EndDate);
                }
            }
            #endregion
        }
        
        #region Automation

        /// <summary>
        /// Provides an implementation of this control as per the WPF structure.
        /// </summary>
        /// <returns>Returns a new AutomationPeer for this type.</returns>
        protected System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer()
        {
  //          return new GestureModuleAutomationPeer(this.surface);
            return null;
        }

        public class GestureModuleAutomationPeer : InkCanvasAutomationPeer
        {
            /// <summary>
            /// Inits a new instance from the base class.
            /// </summary>
            /// <param name="control">The calling control.</param>
            public GestureModuleAutomationPeer(InkCanvas control) 
                : base(control)
            {
                control.StrokeCollected += delegate(object o, InkCanvasStrokeCollectedEventArgs e)
                {
                    RaiseAutomationEvent(AutomationEvents.MenuOpened);
                };
                control.Gesture += delegate(object o, InkCanvasGestureEventArgs e) 
                {
                    RaiseAutomationEvent(AutomationEvents.MenuOpened);
                };
            }

            protected override string GetClassNameCore()
            {
                return "InkCanvas";
            }

            //public void RelayToUIA(object sender, InkCanvasGestureEventArgs e) 
            //{
            //    //if(ListenerExists(AutomationEvents.InvokePatternOnInvoked))
            //        RaiseAutomationEvent(AutomationEvents.PropertyChanged);
            //}
        }

        #endregion
        
    }
}
